package main

import (
	"errors"
	"fmt"
	"strconv"
)

//用一个结构体来模拟一个栈
type Stack struct {
	MaxTop int //栈顶最大值，能存的最大数据量
	Top    int //表示栈顶
	arr    [20]int
}

//如何用两个栈完成加减乘除
func main() {
	numstack := &Stack{
		MaxTop: 20,
		Top:    -1,
	}
	operstack := &Stack{
		MaxTop: 20,
		Top:    -1,
	}
	exp := "30+2*6-9"
	//定义一个index，帮助扫描exp
	index := 0
	num1, num2, oper := 0, 0, 0
	res := 0
	keepnum := ""
	for {
		ch := exp[index : index+1] //string类型
		//ch ==> "+" ==> 43
		temp := int([]byte(ch)[0])
		if IsOperOrNum(temp) { //true的话就是运算符，Push进OperStack
			if operstack.Top == -1 { //如果是空栈就直接Push
				operstack.Push(temp)
			} else {
				if GetIndex(operstack.arr[operstack.Top]) >= GetIndex(temp) { //如果刚入栈的运算符比栈顶优先级小，就先把栈顶的运算符先拿去计算，在把刚入栈的压入
					num1, _ = numstack.Pop()
					num2, _ = numstack.Pop()
					oper, _ = operstack.Pop()
					res = Cal(num1, num2, oper)
					numstack.Push(res)
					operstack.Push(temp)
				} else {
					operstack.Push(temp) //否则直接push
				}
			}
		} else { //否则就是Push进NumStack
			//val,_:= strconv.ParseInt(ch,10,64) //先转成数本值而不是ascii值
			//numstack.Push(int(val))
			//处理多位数的思路：
			//定义一个变量keepnum string 做拼接
			//每次向index后面的字符测试一下看看是不是运算符，不是就直接push进numstack
			//拼接
			keepnum += ch
			//到字符串最后直接入栈
			if index == len(exp)-1 {
				val, _ := strconv.ParseInt(keepnum, 10, 64) //先转成数本值而不是ascii值
				numstack.Push(int(val))
			} else {
				//向index后面的字符测试一下看看是不是运算符
				if IsOperOrNum(int([]byte(exp[index+1 : index+2])[0])) { //是运算符的话就把当前值转化后push
					val, _ := strconv.ParseInt(keepnum, 10, 64) //先转成数本值而不是ascii值
					numstack.Push(int(val))
					keepnum = ""
				}
			}
		}
		if index+1 == len(exp) {
			break
		}
		index++
	}
	for {
		if operstack.Top == -1 {
			break
		}
		num1, _ = numstack.Pop()
		num2, _ = numstack.Pop()
		oper, _ = operstack.Pop()
		res = Cal(num1, num2, oper)
		numstack.Push(res)
	}
	res, _ = numstack.Pop()
	fmt.Println(exp, " 计算结果是：", res)
}

//判断一个字符是不是一个运算符 [42* 43+ 45- 47/]
func IsOperOrNum(val int) bool {
	if val == 42 || val == 43 || val == 45 || val == 47 {
		return true
	} else {
		return false
	}
}

//计算值
func Cal(num1, num2, oper int) int {
	res := 0
	switch oper {
	case 42:
		res = num2 * num1
	case 43:
		res = num2 + num1
	case 45:
		res = num2 - num1
	case 47:
		res = num2 / num1
	default:
		fmt.Println("运算符错误")
	}
	return res
}

//返回运算符的优先级
func GetIndex(oper int) int {
	if oper == 42 || oper == 47 {
		return 1
	} else if oper == 43 || oper == 45 {
		return 0
	}
	return -1
}

//入栈
func (this *Stack) Push(val int) (err error) {
	if this.Top == this.MaxTop-1 { //栈满
		return errors.New("栈满了~")
	}

	this.Top++
	this.arr[this.Top] = val
	return
}

//出栈
func (this *Stack) Pop() (val int, err error) {
	//先判断是否为空
	if this.Top == -1 {
		return -1, errors.New("栈是空的咋弹出啊~")
	}
	val = this.arr[this.Top]
	this.Top--
	return
}

//遍历
func (this *Stack) Show() {
	//先判断是否为空
	if this.Top == -1 {
		fmt.Println("栈是空的咋遍历啊~")
	}
	for curTop := this.Top; curTop >= 0; curTop-- {
		fmt.Printf("栈[%d]:%v\n", curTop, this.arr[curTop])
	}
}
